/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.auth;

import com.je.auth.check.exception.ApiDisabledException;
import com.je.auth.check.exception.NotLoginException;
import com.je.auth.check.exception.TokenException;
import com.je.auth.impl.AbstractAuthLoginManagerImpl;
import com.je.auth.listener.AuthEvent;
import com.je.auth.stp.AuthLoginModel;
import com.je.auth.stp.AuthTokenInfo;
import com.je.auth.util.JwtUtil;
import java.util.Map;

/**
 * Sa-Token 整合 jwt -- stateless 无状态
 *
 * @author kong
 */
public class StatelessJwtAuthLoginManagerImpl extends AbstractAuthLoginManagerImpl {

    /**
     * 获取jwt秘钥
     *
     * @return /
     */
    public String jwtSecretKey() {
        return getConfig().getJwtSecretKey();
    }

    //
    // ------ 重写方法
    //

    // ------------------- 获取token 相关 -------------------

    /**
     * 创建一个TokenValue
     */
    @Override
    public String createTokenValue(Object loginId, String device, long timeout, Map<String, Object> extraData) {
        return JwtUtil.createToken(loginId, device, timeout, extraData, jwtSecretKey());
    }

    /**
     * 获取当前会话的Token信息
     *
     * @return token信息
     */
    @Override
    public AuthTokenInfo getTokenInfo() {
        AuthTokenInfo info = new AuthTokenInfo();
        info.tokenName = getTokenName();
        info.tokenValue = getTokenValue();
        info.isLogin = isLogin();
        info.loginId = getLoginIdDefaultNull();
        info.tokenTimeout = getTokenTimeout();
        info.sessionTimeout = AuthTokenDao.NOT_VALUE_EXPIRE;
        info.tokenSessionTimeout = AuthTokenDao.NOT_VALUE_EXPIRE;
        info.tokenActivityTimeout = AuthTokenDao.NOT_VALUE_EXPIRE;
        info.loginDevice = getLoginDevice();
        return info;
    }

    // ------------------- 登录相关操作 -------------------

    /**
     * 会话登录，并指定所有登录参数Model
     */
    @Override
    public void login(Object id, AuthLoginModel loginModel) {

        TokenException.throwByNull(id, "账号id不能为空");

        // ------ 1、初始化 loginModel
        loginModel.configBuild(getConfig());

        // ------ 2、生成一个token
        String tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData());

        // 3、在当前会话写入tokenValue
        setTokenValue(tokenValue, loginModel.getCookieTimeout());

        // $$ 通知监听器，账号xxx 登录成功
        AuthEvent authEvent = new AuthEvent();
        authEvent.setEventType(AuthEvent.AuthEventType.LOGIN);
        authEvent.setLoginId(id);
        authEvent.setAuthLoginModel(loginModel);
        getAuthEngine().trigger(authEvent);
    }

    /**
     * 获取指定Token对应的账号id (不做任何特殊处理)
     */
    @Override
    public String getLoginIdNotHandle(String tokenValue) {
        // 获取 loginId
        try {
            Object loginId = JwtUtil.getLoginId(tokenValue, jwtSecretKey());
            return String.valueOf(loginId);
        } catch (NotLoginException e) {
            return null;
        }
    }

    /**
     * 会话注销
     */
    @Override
    public void logout() {
        // 从当前 [storage存储器] 里删除
        getAuthEngine().getAuthCheckEngine().getAuthTokenContext().getStorage().delete(splicingKeyJustCreatedSave());
        // 如果打开了Cookie模式，则把cookie清除掉
        if (getAuthEngine().getAuthCheckEngine().getConfig().getIsReadCookie()) {
            getAuthEngine().getAuthCheckEngine().getAuthTokenContext().getResponse().deleteCookie(getTokenName());
        }
    }

    /**
     * 获取Token携带的扩展信息
     */
    @Override
    public Object getExtra(String key) {
        return JwtUtil.getPayloads(getTokenValue(), jwtSecretKey()).get(key);
    }


    // ------------------- 过期时间相关 -------------------

    /**
     * 获取当前登录者的 token 剩余有效时间 (单位: 秒)
     */
    @Override
    public long getTokenTimeout() {
        return JwtUtil.getTimeout(getTokenValue(), jwtSecretKey());
    }

    // ------------------- id 反查 token 相关操作 -------------------

    /**
     * 返回当前会话的登录设备
     *
     * @return 当前令牌的登录设备
     */
    @Override
    public String getLoginDevice() {
        // 如果没有token，直接返回 null
        String tokenValue = getTokenValue();
        if (tokenValue == null) {
            return null;
        }
        // 如果还未登录，直接返回 null
        if (!isLogin()) {
            return null;
        }
        // 获取
        return JwtUtil.getPayloadsNotCheck(tokenValue, jwtSecretKey()).getStr(JwtUtil.DEVICE);
    }

    // ------------------- Bean对象代理 -------------------

    /**
     * [禁用] 返回持久化对象
     */
    @Override
    public AuthTokenDao getAuthTokenDao() {
        throw new ApiDisabledException();
    }


}
